package ran.friend.service.exam.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import ran.constants.Constants;
import ran.entity.TableDataInfo;
import ran.friend.domain.exam.dto.ExamQueryDTO;
import ran.friend.domain.exam.vo.ExamVO;
import ran.friend.manager.ExamRedisCacheManager;
import ran.friend.mapper.exam.ExamMapper;
import ran.friend.service.exam.IExamService;
import ran.utils.ThreadLocalUtil;

import java.util.List;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: ran
 * Date: 2025-11-06
 * Time: 15:07
 */
@Service
@Slf4j
public class ExamServiceImpl implements IExamService {
    @Autowired
    private ExamMapper examMapper;

    @Autowired
    private ExamRedisCacheManager examRedisCacheManager;

    @Override
    public List<ExamVO> list(ExamQueryDTO examQueryDTO) {
        log.info("查询竞赛参数, examQueryDTO:{}",examQueryDTO);
        PageHelper.startPage(examQueryDTO.getPageNum(),examQueryDTO.getPageSize());// 引入分页插件,可以自动在查询条件下加入分页SQL语句
        return examMapper.selectExamList(examQueryDTO);
    }

    // 先查询缓存, 查不到再查询数据库
    @Override
    public TableDataInfo redisList(ExamQueryDTO examQueryDTO) {
        // 从Redis获取竞赛列表数据
        Long total = examRedisCacheManager.getListSize(examQueryDTO.getType(),null);
        List<ExamVO> examVOList;
        if (total == null || total <= 0) {
            // Redis中数据位空, 从数据库中查数据
            examVOList = list(examQueryDTO);

            // 刷新缓存
            examRedisCacheManager.refreshCache(examQueryDTO.getType(),null);

            // 分压插件提供的查询数据总数的方法, 从数据库中查询
            total = new PageInfo<>(examVOList).getTotal();
        }else {
            // 从Redis中查询数据
            examVOList = examRedisCacheManager.getExamVOList(examQueryDTO,null);
            // 再次查询数据, 这是因为在Redis查询数据时,有一旦Redis查询失败,切换成从数据库查询的逻辑
            // 这部分逻辑会再次刷新Redis中的缓存, 所以总数有可能发生变化, 这里需要再次调用, 以便获取最新值的total
            total = examRedisCacheManager.getListSize(examQueryDTO.getType(),null);
        }
        if (CollectionUtil.isEmpty(examVOList)) {
            return TableDataInfo.empty();
        }
        // 这里新添加逻辑, 来给报名字段赋值
        assembleExamEnterList(examVOList);
        return TableDataInfo.success(examVOList,total);
    }

    // 获取竞赛中第一道题目的id 从Redis中查询, 没有的话从数据库查,再刷新缓存
    @Override
    public String getFirstQuestion(Long examId) {
        checkAndRefreshCache(examId);
        return examRedisCacheManager.getFirstQuestion(examId).toString();
    }

    @Override
    public String preQuestion(Long examId, Long questionId) {
        checkAndRefreshCache(examId);
        // 从Redis中查询
        return examRedisCacheManager.preQuestion(examId,questionId).toString();
    }

    @Override
    public String nextQuestion(Long examId, Long questionId) {
        checkAndRefreshCache(examId);
        // 从Redis中查询
        return examRedisCacheManager.nextQuestion(examId,questionId).toString();
    }

    private void checkAndRefreshCache(Long examId) {
        if(examId == null) {
            log.error("examId出现错误: examId:{}",examId);
        }
        Long listSize = examRedisCacheManager.getExamQuestionListSize(examId);
        if (listSize == null || listSize <= 0) {
            examRedisCacheManager.refreshExamQuestionCache(examId);
        }
    }

    // 拼接 enter字段, 继进行赋值
    private void assembleExamEnterList(List<ExamVO> examVOList) {
        Long userId = ThreadLocalUtil.get(Constants.USER_ID, Long.class);
        List<Long> userExamIdList = examRedisCacheManager.getAllUserExamIdList(userId);
        if (CollectionUtil.isEmpty(userExamIdList)) {
            return;
        }
        for (ExamVO examVO : examVOList) {
            if (userExamIdList.contains(examVO.getExamId())) {
                examVO.setEnter(true);
            }
        }
    }
}
